package duppentity.convertors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import duppentity.annotations.Dupp;
import duppentity.dto.Result;
import duppentity.dto.ResultList;
import play.Logger;
import org.apache.commons.lang3.StringUtils;
import utils.JsonUtils;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 默认的结果转换器, 直接输出JsonObject
 * @author zhangzc@djcars.cn
 * @create 2016/8/11
 */
public class DefaultConvertor extends Convertor<Object> {

    static final long ErrorCode = 5000000;

    static final long OkCode = 2000000;

    @Override
    public Object parse(Method method, JsonObject rawResult) {
        Dupp dupp = method.getAnnotation(Dupp.class);
        if(dupp == null){
            throw new RuntimeException("Dupp接口的方法["+method.getName()+"]必须注解@Dupp");
        }

        JsonObject result = null;
        Boolean isError = false;
        Integer errorCode = rawResult.get("state").getAsJsonObject().get("code").getAsInt();
        String errorMsg = "";


        if (errorCode == OkCode && rawResult.has("data") && rawResult.get("data")!=null && !rawResult.get("data").isJsonNull()) {
            result = rawResult.get("data").getAsJsonObject();
        } else {
            if(errorCode > ErrorCode && errorCode < ErrorCode + 1000000){
                errorMsg = rawResult.get("state").getAsJsonObject().get("msg").getAsString();
                if(StringUtils.isEmpty(errorMsg)){
                    errorMsg = rawResult.get("data").getAsString();
                }
                isError = true;
            }else if(errorCode == ErrorCode ){
                //{"code":5000000,"msg":""}
                errorMsg ="服务端错误";
                isError = true;
            }
        }


        //处理返回类型，以及对于List类型的泛型处理
        Class returnType = method.getReturnType(); //返回类型
        Class actualReturnType = returnType; //返回类型的泛型，默认和返回类型一样

        if(result == null){
//            Logger.error("无法获取DUPP[%s]数据", dupp.value());
            if(method.getReturnType().isAssignableFrom(Result.class)){
                Result r =  new Result();
                r.error = isError;
                r.errorCode = errorCode;
                r.errorMsg = errorMsg;
                return JsonUtils.parse(JsonUtils.formatJson(r));
            }else if(method.getReturnType().isAssignableFrom(ResultList.class)){
                ResultList resultList =  new ResultList();
                resultList.error = isError;
                resultList.errorCode = errorCode;
                resultList.errorMsg = errorMsg;
                return JsonUtils.parse(JsonUtils.formatJson(resultList));
                //return resultList;
            }else if(method.getReturnType().isAssignableFrom(List.class)){
                return Collections.EMPTY_LIST;
            }else if(method.getReturnType().equals(JSONObject.class)) {
                return rawResult;
            }else if(method.getReturnType().equals(JsonObject.class)) {
                Result r =  new Result();
                r.error = isError;
                r.errorCode = errorCode;
                r.errorMsg = errorMsg;
                return JsonUtils.parse(JsonUtils.formatJson(r));
            } else{
                return null;
            }
        }


        if(method.getReturnType().isAssignableFrom(Result.class)){
            Type fc = method.getGenericReturnType(); // 关键的地方，如果是List类型，得到其Generic的类型

            if(fc == null){
                Logger.warn("返回的Result必须写明泛型");
                return null;
            }else{
                if(fc instanceof ParameterizedType){//如果是泛型参数的类型
                    ParameterizedType pt = (ParameterizedType) fc;
                    Class genericClazz = (Class)pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象
                    actualReturnType = genericClazz;
                }else{
                    Logger.warn("返回的Result必须写明泛型");
                    return null;
                }
            }
        }else if(method.getReturnType().isAssignableFrom(ResultList.class)){
            Type fc = method.getGenericReturnType(); // 关键的地方，如果是List类型，得到其Generic的类型

            if(fc == null){
                Logger.warn("返回的ResultList必须写明泛型");
                return null;
            }else{
                if(fc instanceof ParameterizedType){//如果是泛型参数的类型
                    ParameterizedType pt = (ParameterizedType) fc;
                    Class genericClazz = (Class)pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象
                    actualReturnType = genericClazz;
                }else{
                    Logger.warn("返回的ResultList必须写明泛型");
                    return null;
                }
            }
        }else if(method.getReturnType().isAssignableFrom(List.class)){
            Type fc = method.getGenericReturnType(); // 关键的地方，如果是List类型，得到其Generic的类型

            if(fc == null){
                Logger.warn("返回的List必须写明泛型");
                return null;
            }else{
                if(fc instanceof ParameterizedType){//如果是泛型参数的类型
                    ParameterizedType pt = (ParameterizedType) fc;
                    Class genericClazz = (Class)pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象
                    actualReturnType = genericClazz;
                }else{
                    Logger.warn("返回的List必须写明泛型");
                    return null;
                }
            }
        }


        Gson gson = new Gson();
        if(method.getReturnType().isAssignableFrom(Result.class)){
            Result _result = new Result<>();
            _result.error = isError;
            _result.errorMsg = errorMsg;
            _result.errorCode = errorCode;

            if(actualReturnType.equals(JsonObject.class)){ //直接返回
                _result.data = result;
                return _result;
            }else if(actualReturnType.equals(boolean.class) || actualReturnType.equals(Boolean.class)){
                _result.data = result.get(dupp.primitiveField()).getAsBoolean();
                return _result;
            }else if(actualReturnType.equals(int.class) || actualReturnType.equals(Integer.class)){
                _result.data = result.get(dupp.primitiveField()).getAsInt();
                return _result;
            }else if(actualReturnType.equals(long.class) || actualReturnType.equals(Long.class)){
                _result.data = result.get(dupp.primitiveField()).getAsLong();
                return _result;
            }else if(actualReturnType.equals(String.class)){
                _result.data = result.get(dupp.primitiveField()).getAsString();
                return _result;
            }else{
                _result.data = JSON.parseObject(result.toString(), actualReturnType);
//            Object r = gson.fromJson(result, returnType);
                return _result;
            }
        }else if(method.getReturnType().isAssignableFrom(ResultList.class)){
            JsonArray arr = result.get("list") != null ? result.get("list").getAsJsonArray() : new JsonArray();
            ResultList resultList = new ResultList(arr.size());
            resultList.total = result.get("total") != null ? result.get("total").getAsInt() : 0;
            resultList.offset = result.get("offset") != null ? result.get("offset").getAsInt() : 0;
            if (result.get("newCount")!=null) {
                resultList.params = result.get("newCount").getAsInt();
            }else{
                resultList.params = 0;
            }
            resultList.lastId = result.get("lastId") != null ? result.get("lastId").getAsLong() : 0;
            for (int i = 0; i < arr.size(); i++) {
                JsonObject e = arr.get(i).getAsJsonObject();
                e.toString();
                Object r = JSON.parseObject(e.toString(), actualReturnType);
//                Object r = gson.fromJson(e, actualReturnType);
                if(r == null){
                    Logger.warn("DefaultConvertor转换对象失败 %s => %s", actualReturnType, e.toString());
                }else{
                    resultList.list.add(r);
                }
            }
            return resultList;
        }else if(method.getReturnType().isAssignableFrom(List.class)){
            JsonArray arr = result.get("list").getAsJsonArray();
            List list = new ArrayList(arr.size());
            for (int i = 0; i < arr.size(); i++) {
                JsonObject e = arr.get(i).getAsJsonObject();
                e.toString();
                Object r = JSON.parseObject(e.toString(), actualReturnType);
//                Object r = gson.fromJson(e, actualReturnType);
                if(r == null){
                    Logger.warn("DefaultConvertor转换对象失败 %s => %s", actualReturnType, e.toString());
                }else{
                    list.add(r);
                }
            }
            return list;
        }

        if(returnType.equals(JsonObject.class)){ //直接返回
            return result;
        }else if(returnType.equals(boolean.class) || returnType.equals(Boolean.class)){
            return result.get(dupp.primitiveField()).getAsBoolean();
        }else if(returnType.equals(int.class) || returnType.equals(Integer.class)){
            return result.get(dupp.primitiveField()).getAsInt();
        }else if(returnType.equals(long.class) || returnType.equals(Long.class)){
            return result.get(dupp.primitiveField()).getAsLong();
        }else if(returnType.equals(String.class)){
            return result.get(dupp.primitiveField()).getAsString();
        }else{
            Object r = JSON.parseObject(result.toString(), returnType);
//            Object r = gson.fromJson(result, returnType);
            return r;
        }
    }


}
